﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Collections;
using DongleTest.Properties;
using System.Threading;

namespace DongleTest
{
    public class DongleManager
    {
        /// <summary>
        /// 串口
        /// </summary>
        private SerialPort serialPort = null;

        /// <summary>
        /// 超时时间
        /// </summary>
        private int timeout = 5000;

        private bool isClosing = false;

        /// <summary>
        /// 是否正在接收数据
        /// </summary>
        private bool isReceving = false;

        /// <summary>
        ///  设备初始化是否成功
        /// </summary>
        private bool isInit = false;

        /// <summary>
        ///  检索是否结束
        /// </summary>
        private bool isEndSearch = false;

        /// <summary>
        /// 是否正在绘制波形
        /// </summary>
        public bool isDrawing = false;

        /// <summary>
        /// 设备是否连接
        /// </summary>
        public bool isConnected = false;

        /// <summary>
        /// 写入值是否成功
        /// </summary>
        public bool isWriteCharValueSuccess = false;

        /// <summary>
        /// 是否因为timeout断开连接
        /// </summary>
        public bool isTerminateLinkBecauseTimeout = false;

        /// <summary>
        /// 已连接设备mac
        /// </summary>
        private string connectedMac = string.Empty;

        /// <summary>
        /// 通知是否打开
        /// </summary>
        private bool isNotify = false;

        /// <summary>
        /// 测试结果
        /// </summary>
        private int testResult = -1;

        /// <summary>
        /// 串口名字
        /// </summary>
        public string PortName = string.Empty;

        /// <summary>
        /// 波特率
        /// </summary>
        public string BaudRate = string.Empty;

        /// <summary>
        /// 数据位
        /// </summary>
        public string DataBits = string.Empty;

        /// <summary>
        /// 奇偶检验
        /// </summary>
        public string Parity = string.Empty;

        /// <summary>
        /// 停止位
        /// </summary>
        public string StopBits = string.Empty;

        /// <summary>
        /// 检索到的蓝牙信息
        /// </summary>
        private Hashtable btInfo = new Hashtable();

        /// <summary>
        /// 当前蓝牙信号强度
        /// </summary>
        private sbyte curRssi = 0;

        /// <summary>
        /// 该属性是否可以写入
        /// </summary>
        private bool isCanWrite = false;

        /// <summary>
        /// 状态改变
        /// </summary>
        /// <param name="code">ERR: 错误  OK:正常</param>
        /// <param name="state"></param>
        public delegate void StateChangedHandler(string code, string state);
        public event StateChangedHandler StateChanged;

        public delegate void DrawWaveHandler(int x, int y, int z);
        public event DrawWaveHandler DrawWave;

        /// <summary>
        /// dongle的mac地址
        /// </summary>
        public string Mac = "";

        /// <summary>
        /// 构造函数
        /// </summary>
        public DongleManager()
        {
            serialPort = new SerialPort();
            PortName = "COM1";
            BaudRate = "9600";
            DataBits = "8";
            Parity = "None";
            StopBits = "One";
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="portName"></param>
        /// <param name="baudRate"></param>
        /// <param name="dataBits"></param>
        /// <param name="parity"></param>
        /// <param name="stopBits"></param>
        public DongleManager(string portName, string baudRate, string dataBits, string parity, string stopBits)
        {
            serialPort = new SerialPort();
            PortName = portName;
            BaudRate = baudRate;
            DataBits = dataBits;
            Parity = parity;
            StopBits = stopBits;
        }

        /// <summary>
        /// 串口数据读取
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            if (isClosing)
            {
                return;
            }
            try
            {
                //***正在接收状态指示。
                isReceving = true;
                //读入收到的数据。
                int Len = serialPort.BytesToRead;
                if (Len < 1)
                {
                    //***接收完成状态指示。
                    isReceving = false;
                    return;
                }

                byte[] data = new byte[Len];
                serialPort.Read(data, 0, Len);
                Analysis(data);

            }
            catch (Exception Err)
            {
                MessageBox.Show(Err.Message);
            }
            finally
            {
                isReceving = false;
            }

        }

        /// <summary>
        /// 解析收到的信息
        /// </summary>
        /// <param name="hex"></param>
        private void Analysis(byte[] btRe)
        {
            byte[] bt = btRe;
            int startPos = 0;
            string str = string.Empty;

            try
            {
                if (btRe.Length > 6)
                {
                    while (bt != null && bt.Length > 0)
                    {
                        byte[] newBt = SubBytes(bt, 0, 6);
                        GAP.GAP_Read read = new GAP.GAP_Read();
                        read = (GAP.GAP_Read)Convertor.BytesToStruct(newBt, typeof(GAP.GAP_Read));
                        ushort even = (ushort)((read.Event[1] << 8) | read.Event[0]);
                        str = string.Empty;

                        switch (even)
                        {

                            #region 设备搜索结束
                            case Common.Event.GAP_DeviceDiscoveryDone:
                                isEndSearch = true;
                                // str = "设备搜索结束";
                                break;
                            #endregion

                            #region 检索到的设备信息
                            case Common.Event.GAP_DeviceInformation:

                                if (bt.Length > 16)
                                {
                                    byte[] tempBt = SubBytes(bt, 0, 16);
                                    GAP.GAP_DeviceInformation info = new GAP.GAP_DeviceInformation();
                                    info = (GAP.GAP_DeviceInformation)Convertor.BytesToStruct(tempBt, typeof(GAP.GAP_DeviceInformation));
                                    string addr = Convertor.ConvertToAddrStr(info.Addr);
                                    byte[] newbe = SubBytes(bt, 16, bt.Length - 16);
                                    string name = System.Text.Encoding.Default.GetString(newbe);
                                    str = " 物理地址:" + addr + "信号强度：" + info.Rssi;
                                    Console.WriteLine(str);
                                    if (btInfo.Count == Settings.Default.SearchCount)
                                    {
                                        SearchCancel();
                                        isEndSearch = true;
                                    }
                                    if (!btInfo.ContainsKey(addr))
                                    {
                                        btInfo.Add(addr, info.Rssi);
                                    }
                                    if (info.Rssi > -35)
                                    {
                                        SearchCancel();
                                    }

                                }
                                break;
                            #endregion

                            #region 设备初始化结束
                            case Common.Event.GAP_DeviceInitDone:
                                //str = "设备初始化结束";
                                if (bt.Length >= 12)
                                {
                                    byte[] tempBt = SubBytes(bt, 6, 6);
                                    tempBt.Reverse();
                                    Mac = Convertor.ConvertToAddrStr(tempBt);
                                }
                                isInit = true;
                                break;
                            #endregion

                            #region 连接建立完毕，更新连接参数
                            case Common.Event.GAP_LinkParamUpdate:
                                // str = "连接建立完毕，更新连接参数";
                                //str = " 建立连接";
                                //isConnected = true;
                                break;
                            #endregion

                            #region 开始建立连接
                            case Common.Event.GAP_EstablishLink:
                                str = " 建立连接";
                                isConnected = true;
                                isTerminateLinkBecauseTimeout = false;
                                break;
                            #endregion

                            #region 断开连接
                            case Common.Event.GAP_TerminateLink:
                                if (bt.Length == 9)
                                {
                                    if (bt[8] == 8)
                                    {
                                        isTerminateLinkBecauseTimeout = true;
                                    }
                                }
                                break;
                            #endregion

                            #region 命令执行状态
                            case Common.Event.GAP_HCI_ExtentionCommandStatus:
                                if (bt.Length >= 9)
                                {
                                    byte[] tempBt = SubBytes(bt, 0, 9);
                                    GAP.GAP_HCI_ExtentionCommandStatus info = new GAP.GAP_HCI_ExtentionCommandStatus();
                                    info = (GAP.GAP_HCI_ExtentionCommandStatus)Convertor.BytesToStruct(tempBt, typeof(GAP.GAP_HCI_ExtentionCommandStatus));

                                    if (info.Status == Common.Status.Success)
                                    {
                                        if (info.OpCode == new byte[] { 0x92, 0xFD })
                                        {
                                            isWriteCharValueSuccess = true;
                                        }
                                        str = " 命令执行成功";
                                    }
                                    else
                                    {
                                        str = " 命令执行失败";
                                    }
                                }
                                else
                                {
                                    str = " 命令解析失败";
                                }
                                break;
                            #endregion

                            #region 检索信息应答
                            case Common.Event.ATT_FindInfoRsp:
                                //str = "检索信息应答";
                                //if (bt.Length > 11)
                                //{
                                //    byte[] tempBt = SubBytes(bt, 0, 11);
                                //    GAP.ATT_FindInfoRsp info = new GAP.ATT_FindInfoRsp();
                                //    info = (GAP.ATT_FindInfoRsp)Convertor.BytesToStruct(tempBt, typeof(GAP.ATT_FindInfoRsp));
                                //    if (info.Status != Common.Status.Completed)
                                //    {
                                //        byte[] newbe = SubBytes(bt, 11, bt.Length - 11);
                                //        if (info.Format == Common.Format.UUID)
                                //        {
                                //            for (int i = 0; i < newbe.Length / 4; i++)
                                //            {
                                //                byte[] handle = SubBytes(newbe, i * 2, 2);
                                //                byte[] uuid = SubBytes(newbe, (i + 1) * 2, 2);
                                //            }
                                //        }
                                //        else
                                //        {
                                //            byte[] handle = SubBytes(newbe, 0, 2);
                                //            byte[] uuid = SubBytes(newbe, 2, newbe.Length - 2);
                                //        }

                                //    }

                                //}
                                break;
                            #endregion

                            #region FFF1写入反馈
                            case Common.Event.ATT_HandleValueNotification:
                                if (bt.Length > 15)
                                {
                                    byte[] test = SubBytes(bt, 11, 4);
                                    byte[] newbe = SubBytes(bt, 15, bt.Length - 15);
                                    byte[] sensor = SubBytes(newbe, 0, 3);
                                    byte[] pcba = SubBytes(newbe, 3, 3);
                                    byte[] eeprom = SubBytes(newbe, 6, 3);
                                    byte[] xyz = SubBytes(bt, 13, 18);
                                    switch (Convertor.ConvertToNameStr(test))
                                    {
                                        case "TEST":
                                            int result = 0;
                                            if (Convertor.ConvertToNameStr(sensor).Equals("OKK"))
                                            {
                                                result += 4;
                                                if (StateChanged != null)
                                                {
                                                    StateChanged("OK", "传感器测试成功");
                                                }
                                            }
                                            else
                                            {
                                                result += 4;
                                                //if (StateChanged != null)
                                                //{
                                                //StateChanged("OK", "传感器测试成功");
                                                //StateChanged("ERR", "传感器错误");
                                                //}
                                            }
                                            if (Convertor.ConvertToNameStr(pcba).Equals("OKK"))
                                            {
                                                result += 2;
                                                if (StateChanged != null)
                                                {
                                                    StateChanged("OK", "PCBA测试成功");
                                                }
                                            }
                                            else
                                            {
                                                if (StateChanged != null)
                                                {
                                                    StateChanged("ERR", "PCBA错误");
                                                }
                                            }
                                            if (Convertor.ConvertToNameStr(eeprom).Equals("OKK"))
                                            {
                                                result += 1;
                                                if (StateChanged != null)
                                                {
                                                    StateChanged("OK", "EEPROM测试成功");
                                                }
                                            }
                                            else
                                            {
                                                if (StateChanged != null)
                                                {
                                                    StateChanged("ERR", "EEPROM错误");
                                                }
                                            }
                                            testResult = result;
                                            break;

                                        //case "LEON":
                                        //    str = "LED打开:";
                                        //    break;
                                        //case "LEOF":
                                        //    str = "LED关闭";
                                        //    break;
                                        case "Z":
                                            isDrawing = true;
                                            if (DrawWave != null)
                                            {
                                                short x = Convertor.BytesToShort(new byte[] { xyz[0], xyz[1] });
                                                short y = Convertor.BytesToShort(new byte[] { xyz[2], xyz[3] });
                                                short z = Convertor.BytesToShort(new byte[] { xyz[4], xyz[5] });

                                                //short x = BitConverter.ToInt16(xyz, 0);
                                                //short y = BitConverter.ToInt16(xyz, 2);
                                                //short z = BitConverter.ToInt16(xyz, 4);
                                                DrawWave(x, y, z);

                                                x = Convertor.BytesToShort(new byte[] { xyz[6], xyz[7] });
                                                y = Convertor.BytesToShort(new byte[] { xyz[8], xyz[9] });
                                                z = Convertor.BytesToShort(new byte[] { xyz[10], xyz[11] });

                                                //x = BitConverter.ToInt16(xyz, 6);
                                                //y = BitConverter.ToInt16(xyz, 8);
                                                //z = BitConverter.ToInt16(xyz, 10);
                                                DrawWave(x, y, z);

                                                x = Convertor.BytesToShort(new byte[] { xyz[12], xyz[13] });
                                                y = Convertor.BytesToShort(new byte[] { xyz[14], xyz[15] });
                                                z = Convertor.BytesToShort(new byte[] { xyz[16], xyz[17] });

                                                //x = BitConverter.ToInt16(xyz, 12);
                                                //y = BitConverter.ToInt16(xyz, 14);
                                                //z = BitConverter.ToInt16(xyz, 16);
                                                DrawWave(x, y, z);
                                            }
                                            break;
                                        default: break;
                                    }
                                }
                                break;
                            #endregion

                            #region 开启FFF2
                            case Common.Event.ATT_WriteRsp:
                                if (bt.Length >= 9)
                                {
                                    byte[] tempBt = SubBytes(bt, 0, 9);
                                    GAP.ATT_WriteRsp info = new GAP.ATT_WriteRsp();
                                    info = (GAP.ATT_WriteRsp)Convertor.BytesToStruct(tempBt, typeof(GAP.ATT_WriteRsp));
                                    if (info.Status == Common.Status.Success)
                                    {
                                        isNotify = true;
                                    }
                                }
                                break;
                            #endregion

                            #region RSSI
                            case Common.Event.HCI_ReadRSSI:
                                if (bt.Length >= 10)
                                {
                                    byte[] tempBt = SubBytes(bt, 0, 10);
                                    GAP.HCI_ReadRSSI info = new GAP.HCI_ReadRSSI();
                                    info = (GAP.HCI_ReadRSSI)Convertor.BytesToStruct(tempBt, typeof(GAP.HCI_ReadRSSI));
                                    curRssi = info.RSSI;
                                }
                                break;
                            #endregion

                            #region 读取反馈
                            case Common.Event.ATT_ReadRsp:
                                if (bt.Length >= 9)
                                {
                                    byte[] tempBt = SubBytes(bt, 0, 9);
                                    GAP.ATT_ReadRsp info = new GAP.ATT_ReadRsp();
                                    info = (GAP.ATT_ReadRsp)Convertor.BytesToStruct(tempBt, typeof(GAP.ATT_ReadRsp));
                                    byte[] value = SubBytes(bt, 9, bt.Length - 9);
                                    if (value.Length == 2 && value[0] == 1 && value[1] == 0)
                                    {
                                        isCanWrite = true;
                                    }
                                    else
                                    {
                                        isCanWrite = false;
                                    }
                                }
                                break;
                            #endregion

                            default: break;
                        }
                        startPos += 3 + read.DataLength;
                        bt = SubBytes(btRe, startPos, btRe.Length - startPos);
                    }
                }
            }
            catch (Exception ee)
            {
                Console.WriteLine(ee.Message);
            }
        }

        /// <summary>
        /// 打开串口
        /// </summary>
        private bool OpenPort()
        {
            isClosing = false;
            try
            {
                //自动获取串行口名称
                //foreach (string port in PortInfo.SerialPort())
                //{
                //    if (port.ToUpper().Contains("CC2540"))
                //    {
                //        PortName = port.ToUpper();
                //        break;
                //    }
                //}
                //***避免串口死锁***
                //写超时，如果底层串口驱动效率问题，能有效的避免死锁。
                serialPort.WriteTimeout = timeout;
                //读超时，同上。
                serialPort.ReadTimeout = timeout;
                //回车换行。
                serialPort.NewLine = "\r\n";
                //注册事件。
                serialPort.DataReceived += new SerialDataReceivedEventHandler(this.serialPort_DataReceived);
                //***避免串口死锁***
                Regex reg = new Regex("COM[0-9]{1,2}");
                serialPort.PortName = reg.Match(PortName).Value;
                serialPort.BaudRate = int.Parse(BaudRate);
                serialPort.DataBits = int.Parse(DataBits);
                serialPort.Parity = (Parity)Enum.Parse(typeof(Parity), Parity);
                serialPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), StopBits);
                serialPort.Open();

                TimeoutChecker tc = new TimeoutChecker(
                  delegate
                  {
                      while (!serialPort.IsOpen)
                      {
                          Application.DoEvents();
                      }
                  },
                  delegate
                  {
                      MessageBox.Show("串口打开超时");
                  });

                tc.Wait(Settings.Default.OpenPortTime);
                isInit = false;
                return true;
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
                return false;
            }
        }

        /// <summary>
        /// 关闭串口
        /// </summary>
        private void ClosePort()
        {

            if (serialPort.IsOpen)
            {
                if (isConnected)
                {
                    TerminateLink();

                }
                //安全关闭当前串口。
                //注销串口中断接收事件，避免下次再执行进来，造成死锁。
                serialPort.DataReceived -= serialPort_DataReceived;


                while (isReceving)
                {
                    //处理串口接收事件及其它系统消息。
                    Application.DoEvents();
                }

                isClosing = true;
                //现在没有死锁，可以关闭串口。
                serialPort.Close();
                isClosing = false;
                //***避免串口死锁***
            }
        }

        /// <summary>
        /// UsbDongle初始化
        /// </summary>
        public bool InitUsbDongle()
        {
            if (!serialPort.IsOpen)
            {
                if (!OpenPort())
                {
                    return false;
                }
            }
            //设备初始化
            GAP.GAP_DeviceInit init = new GAP.GAP_DeviceInit();
            init.Type = 0x01;
            init.OpCode = Convertor.HexToByte("00 FE");
            init.DataLength = 0X26;
            init.ProfileRole = 0X08;
            init.MaxScanRsps = Settings.Default.SearchCount;
            init.IRK = Convertor.HexToByte("00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00");
            init.CSRK = Convertor.HexToByte("00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00");
            init.SignCounter = Convertor.HexToByte("01 00 00 00 ");
            byte[] bt = Convertor.StructToBytes(init, Marshal.SizeOf(init));
            serialPort.Write(bt, 0, bt.Length);

            TimeoutChecker tc = new TimeoutChecker(
                 delegate
                 {
                     while (!isInit)
                     {
                         Application.DoEvents();
                     }
                 },
                 delegate
                 {
                     isInit = false;
                     MessageBox.Show("初始化失败！");
                 });

            tc.Wait(Settings.Default.InitPortTime);
            SetParam();
            if (isInit)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 设置连接参数
        /// </summary>
        private void SetParam()
        {
            byte[] bt1 = new byte[] { 0x01, 0x30, 0xFE, 0x03, 0x15, 0x08, 0x00 };
            serialPort.Write(bt1, 0, bt1.Length);
            Thread.Sleep(20);
            byte[] bt2 = new byte[] { 0x01, 0x30, 0xFE, 0x03, 0x16, 0x08, 0x00 };
            serialPort.Write(bt2, 0, bt2.Length);
            Thread.Sleep(20);
            byte[] bt3 = new byte[] { 0x01, 0x30, 0xFE, 0x03, 0x1A, 0x00, 0x00 };
            serialPort.Write(bt3, 0, bt3.Length);
            Thread.Sleep(20);
            byte[] bt4 = new byte[] { 0x01, 0x30, 0xFE, 0x03, 0x19, 0xD0, 0x07 };
            serialPort.Write(bt4, 0, bt4.Length);
            //            [1] : <Tx> - 10:13:24.571
            //-Type           : 0x01 (Command)
            //-OpCode         : 0xFE30 (GAP_SetParam)
            //-Data Length    : 0x03 (3) byte(s)
            // ParamID        : 0x15 (21) (Minimum Link Layer Connection Interval, 
            //                  When Using Connection Establishment 
            //                  Proc (mSec). TGAP_CONN_EST_INT_MIN)
            // ParamValue     : 0x0050 (80)
            //Dump(Tx):
            //0000:01 30 FE 03 15 50 00                            .0...P.
            //--------------------------------------------------------------------
            //[2] : <Tx> - 10:13:24.603
            //-Type           : 0x01 (Command)
            //-OpCode         : 0xFE30 (GAP_SetParam)
            //-Data Length    : 0x03 (3) byte(s)
            // ParamID        : 0x16 (22) (Maximum Link Layer Connection Interval, 
            //                  When Using Connection Establishment 
            //                  Proc (mSec). TGAP_CONN_EST_INT_MAX)
            // ParamValue     : 0x0050 (80)
            //Dump(Tx):
            //0000:01 30 FE 03 16 50 00                            .0...P.
            //--------------------------------------------------------------------
            //[3] : <Tx> - 10:13:24.618
            //-Type           : 0x01 (Command)
            //-OpCode         : 0xFE30 (GAP_SetParam)
            //-Data Length    : 0x03 (3) byte(s)
            // ParamID        : 0x1A (26) (Link Layer Connection Slave Latency, When Using 
            //                  Connection Establishment Proc (mSec) TGAP_CONN_EST_LATENCY)
            // ParamValue     : 0x0000 (0)
            //Dump(Tx):
            //0000:01 30 FE 03 1A 00 00                            .0.....
            //--------------------------------------------------------------------
            //[4] : <Tx> - 10:13:24.634
            //-Type           : 0x01 (Command)
            //-OpCode         : 0xFE30 (GAP_SetParam)
            //-Data Length    : 0x03 (3) byte(s)
            // ParamID        : 0x19 (25) (Link Layer Connection Supervision Timeout, 
            //                  When Using Connection Establishment 
            //                  Proc (mSec). TGAP_CONN_EST_SUPERV_TIMEOUT)
            // ParamValue     : 0x07D0 (2000)
            //Dump(Tx):
            //0000:01 30 FE 03 19 D0 07    
        }

        /// <summary>
        /// 连接到蓝牙设备
        /// </summary>
        /// <param name="mac"></param>
        public bool LinkTo(string mac)
        {
            if (!serialPort.IsOpen)
            {
                if (!OpenPort())
                {
                    return false;
                }
            }
            if (!isInit)
            {
                if (!InitUsbDongle())
                {
                    return false;
                }
            }

            // 发送连接命令
            GAP.GAP_EstablishLinkRequest link = new GAP.GAP_EstablishLinkRequest();
            link.Type = 0x01;
            link.OpCode = Convertor.HexToByte("09 FE");
            link.DataLength = 0x09;
            link.HighDutyCycle = 0x00;
            link.WhiteList = 0x00;
            link.AddrTypePeer = 0x00;
            link.PeerAddr = Convertor.ConvertToAddrBytes(mac);
            byte[] bt = Convertor.StructToBytes(link, Marshal.SizeOf(link));

            serialPort.Write(bt, 0, bt.Length);
            connectedMac = mac;

            // 等待连接结束
            TimeoutChecker tc = new TimeoutChecker(
                 delegate
                 {
                     while (!isConnected)
                     {
                         Application.DoEvents();
                     }
                 },
                 delegate
                 {
                     connectedMac = string.Empty;
                     isConnected = false;
                 });

            tc.Wait(Settings.Default.LinkTime);

            if (isConnected)
            {
                if (StateChanged != null)
                {
                    StateChanged("OK", "连接成功");
                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        public void TerminateLink()
        {
            if (this.serialPort.IsOpen)
            {
                //GAP.GAP_TerminateLinkRequest link = new GAP.GAP_TerminateLinkRequest();
                //link.Type = 0x01;
                //link.OpCode = Convertor.HexToByte("0A FE");
                //link.DataLength = 0x03;
                //link.ConnHandle = new byte[] { 0x00, 0x00 };
                //link.DiscReason = Common.DiscReason.Remote_User_Terminated;
                //byte[] bt = Convertor.StructToBytes(link, Marshal.SizeOf(link));
                //serialPort.Write(bt, 0, bt.Length);
                byte[] bt = new byte[] { 0x01, 0x0A, 0xFE, 0x03, 0x00, 0x00, 0x13 };
                //byte[] bt = new byte[] { 0x01, 0x0A, 0xFE, 0x02, 0x00, 0x00 };
                serialPort.Write(bt, 0, bt.Length);
                Thread.Sleep(1000);
            }

            isConnected = false;
            connectedMac = string.Empty;
        }

        /// <summary>
        /// 打开FFF2通知服务
        /// </summary>
        private bool OpenNotify(string mac, byte[] handle)
        {
            if (!isConnected)
            {
                if (!LinkTo(mac))
                {
                    return false;
                }
            }
            isNotify = false;

            if (ReadCharFFF2(handle))
            {
                isNotify = true;
                return true;
            }
            // 发送命令
            GAP.GATT_WriteCharValueFFF2 notify = new GAP.GATT_WriteCharValueFFF2();
            notify.Type = 0x01;
            notify.OpCode = Convertor.HexToByte("92 FD");
            notify.DataLength = 0x06;
            notify.ConnHandle = new byte[] { 0x00, 0x00 };
            notify.Handle = handle;
            notify.Value = new byte[] { 0x01, 0x00 };
            byte[] bt = Convertor.StructToBytes(notify, Marshal.SizeOf(notify));
            serialPort.Write(bt, 0, bt.Length);

            // 等待连接结束
            TimeoutChecker tc = new TimeoutChecker(
                 delegate
                 {
                     while (!isNotify)
                     {
                         Application.DoEvents();
                     }
                 },
                 delegate
                 {
                     //if (StateChanged != null)
                     //{
                     //    StateChanged("ERR", "打开通知服务超时");
                     //}
                 });

            tc.Wait(Settings.Default.NotifyTime);

            //if (isNotify)
            //{
            //    return true;
            //}
            return true;
        }

        /// <summary>
        /// 测试蓝牙设备
        /// </summary>
        /// <param name="mac"></param>
        /// <returns></returns>
        public int TestTo(string mac)
        {
            if (!OpenNotify(mac, new byte[] { 0x29, 0x00 }))
            {
                return -1;
            }

            testResult = -1;
            GAP.GATT_WriteCharValueFFF1 test = new GAP.GATT_WriteCharValueFFF1();
            test.Type = 0x01;
            test.OpCode = Convertor.HexToByte("92 FD");
            test.DataLength = 0x18;
            test.ConnHandle = new byte[] { 0x00, 0x00 };
            test.Handle = new byte[] { 0x25, 0x00 };
            test.Value = new byte[] { 0x54, 0x45, 0x53, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
            byte[] bt = Convertor.StructToBytes(test, Marshal.SizeOf(test));
            serialPort.Write(bt, 0, bt.Length);

            // 等待测试结束
            TimeoutChecker tc = new TimeoutChecker(
                 delegate
                 {
                     while (testResult == -1)
                     {
                         Application.DoEvents();
                     }
                 },
                 delegate
                 {
                     if (StateChanged != null)
                     {
                         StateChanged("ERR", "测试超时");
                     }
                 });

            tc.Wait(Settings.Default.TestTime);

            return testResult;
        }

        /// <summary>
        /// 绘制波形
        /// </summary>
        /// <param name="mac"></param>
        /// <returns></returns>
        public bool StartDrawWave(string mac)
        {
            if (!OpenNotify(mac, new byte[] { 0x30, 0x00 }))
            {
                return false;
            }
            Thread.Sleep(100);
            isDrawing = false;
            GAP.GATT_WriteCharValueFFF3 test = new GAP.GATT_WriteCharValueFFF3();
            test.Type = 0x01;
            test.OpCode = Convertor.HexToByte("92 FD");
            test.DataLength = 0x08;
            test.ConnHandle = new byte[] { 0x00, 0x00 };
            test.Handle = new byte[] { 0x2C, 0x00 };
            //test.Value = new byte[] { 0x47, 0x41, 0x4D, 0x45 };  //GAME
            test.Value = new byte[] { 0x52, 0x45, 0x41, 0x4C }; //REAL
            byte[] bt = Convertor.StructToBytes(test, Marshal.SizeOf(test));
            serialPort.Write(bt, 0, bt.Length);

            // 等待测试结束
            TimeoutChecker tc = new TimeoutChecker(
                 delegate
                 {
                     while (!isDrawing)
                     {
                         Application.DoEvents();
                     }
                 },
                 delegate
                 {
                     isDrawing = false;
                 });
            tc.Wait(Settings.Default.WaveTime);

            if (isDrawing)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 停止绘制波形
        /// </summary>
        /// <param name="mac"></param>
        /// <returns></returns>
        public void EndDrawWave()
        {
            GAP.GATT_WriteCharValueFFF3 test = new GAP.GATT_WriteCharValueFFF3();
            test.Type = 0x01;
            test.OpCode = Convertor.HexToByte("92 FD");
            test.DataLength = 0x08;
            test.ConnHandle = new byte[] { 0x00, 0x00 };
            test.Handle = new byte[] { 0x2C, 0x00 };
            test.Value = new byte[] { 0x52, 0x45, 0x4F, 0x46 };
            byte[] bt = Convertor.StructToBytes(test, Marshal.SizeOf(test));
            serialPort.Write(bt, 0, bt.Length);
            Thread.Sleep(100);
            isDrawing = false;
        }

        /// <summary>
        /// 释放串口
        /// </summary>
        public void Dispose()
        {
            if (this.serialPort != null)
            {
                ClosePort();
            }
        }

        /// <summary>
        /// 截取byte数组
        /// </summary>
        /// <param name="bt"></param>
        /// <param name="start"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        private byte[] SubBytes(byte[] bt, int start, int length)
        {
            if (start < 0 || length <= 0)
            {
                return null;
            }
            byte[] tempBt = new byte[length];
            for (int i = 0; i < length; i++)
            {
                tempBt[i] = bt[start + i];
            }
            return tempBt;
        }

        /// <summary>
        /// 获取最近的蓝牙设备Mac
        /// </summary>
        /// <returns></returns>
        public string NearestMac()
        {
            string mac = string.Empty;
            if (!isInit || !this.serialPort.IsOpen)
            {
                if (!InitUsbDongle())
                {
                    return mac;
                }
            }
            sbyte rssi = -128;
            int times = 0;
            while (string.IsNullOrEmpty(mac))
            {
                Search();

                if (times > Settings.Default.SearchTimes)
                {
                    break;
                }
                rssi = -128;

                foreach (string key in btInfo.Keys)
                {
                    if ((sbyte)btInfo[key] > rssi)
                    {
                        rssi = (sbyte)btInfo[key];
                        mac = key;
                    }
                }
                if (rssi < Settings.Default.Rssi)
                {
                    mac = string.Empty;
                }

                times++;
            }

            return mac;
        }

        /// <summary>
        /// 搜索蓝牙设备
        /// </summary>
        private int Search()
        {
            btInfo.Clear();
            isEndSearch = false;
            // 搜索蓝牙设备
            GAP.GAP_DeviceDiscoveryRequest request = new GAP.GAP_DeviceDiscoveryRequest();
            request.Type = 0x01;
            request.OpCode = Convertor.HexToByte("04 FE");
            request.DataLength = 0x03;
            request.Mode = 0x03;
            request.ActiveScan = 0x01;
            request.WhiteList = 0x00;
            byte[] bt = Convertor.StructToBytes(request, Marshal.SizeOf(request));
            serialPort.Write(bt, 0, bt.Length);

            // 等待测试结束
            TimeoutChecker tc = new TimeoutChecker(
                 delegate
                 {
                     while (!isEndSearch)
                     {
                         Application.DoEvents();
                     }
                 },
                 delegate
                 {
                     isEndSearch = false;
                     SearchCancel();
                 });

            tc.Wait(Settings.Default.SearchTime);
            return btInfo.Count;
        }

        /// <summary>
        /// 搜索蓝牙设备取消
        /// </summary>
        private void SearchCancel()
        {
            // 搜索蓝牙设备
            GAP.GAP_DeviceDiscoveryCancel cancel = new GAP.GAP_DeviceDiscoveryCancel();
            cancel.Type = 0x01;
            cancel.OpCode = Convertor.HexToByte("05 FE");
            cancel.DataLength = 0x00;
            byte[] bt = Convertor.StructToBytes(cancel, Marshal.SizeOf(cancel));
            serialPort.Write(bt, 0, bt.Length);
            isEndSearch = false;
        }

        /// <summary>
        /// 获取蓝牙设备RSSI
        /// </summary>
        /// <returns></returns>
        public sbyte ReadRssi(string mac)
        {
            if (!isConnected)
            {
                return 0;
            }


            GAP.HCI_ReadRSSI_RSP rssi = new GAP.HCI_ReadRSSI_RSP();
            rssi.Type = 0x01;
            rssi.OpCode = Convertor.HexToByte("05 14");
            rssi.DataLength = 0x02;
            rssi.ConnHandle = Convertor.HexToByte("00 00");
            byte[] bt = Convertor.StructToBytes(rssi, Marshal.SizeOf(rssi));
            serialPort.Write(bt, 0, bt.Length);

            Thread.Sleep(50);
            return curRssi;
        }

        /// <summary>
        /// 获取特征值开关
        /// </summary>
        /// <returns></returns>
        public bool ReadCharFFF2(byte[] handle)
        {
            isCanWrite = false;
            GAP.GATT_ReadCharDesc read = new GAP.GATT_ReadCharDesc();
            read.Type = 0x01;
            read.OpCode = Convertor.HexToByte("BC FD");
            read.DataLength = 0x04;
            read.ConnHandle = new byte[] { 0x00, 0x00 };
            read.Handle = handle;// new byte[] { 0x29, 0x00 };
            byte[] bt = Convertor.StructToBytes(read, Marshal.SizeOf(read));
            serialPort.Write(bt, 0, bt.Length);
            Thread.Sleep(100);
            return isCanWrite;
        }

        /// <summary>
        /// 写入特征值
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool GATTWriteCharValue(byte[] handle, byte[] value)
        {
            byte Type = 0x01;
            byte[] OpCode = Convertor.HexToByte("92 FD");
            byte[] ConnHandle = new byte[] { 0x00, 0x00 };
            byte[] Handle = handle;
            byte[] Value = value;
            byte DataLength = (byte)(ConnHandle.Length + Handle.Length + Value.Length);
            List<byte> bt = new List<byte>();
            bt.Add(Type);
            bt.AddRange(OpCode);
            bt.Add(DataLength);
            bt.AddRange(Handle);
            bt.AddRange(Value);
            isWriteCharValueSuccess = false;
            serialPort.Write(bt.ToArray(), 0, bt.Count);
            Thread.Sleep(100);
            return isWriteCharValueSuccess;

        }

        /// <summary>
        /// 写入特征值
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool GATTWriteString(GATTHandle handle, string value)
        {
            byte[] newHandle = new byte[] { (byte)handle, 0 };
            byte[] newValue = Encoding.Default.GetBytes(value);
            return GATTWriteCharValue(newHandle, newValue);
        }

        /// <summary>
        /// 几种常见的蓝牙服务
        /// </summary>
        public enum GATTHandle
        {
            /// <summary>
            /// 可写入的服务
            /// </summary>
            FFF1 = 37,

            /// <summary>
            /// NOTIFY的服务
            /// </summary>
            FFF2 = 40,

            /// <summary>
            /// 写入01:00打开NOTIFY
            /// </summary>
            /// 
            FFF2_OPEN_NOTIFY = 41,

            /// <summary>
            /// 可写入的服务
            /// </summary>
            FFF3 = 44,

            /// <summary>
            /// NOTIFY的服务
            /// </summary>
            FFF4 = 47,

            /// <summary>
            /// 写入01:00打开NOTIFY
            /// </summary>
            FFF4_OPEN_NOTIFY = 48

        }
    }
}
